
#include <string>
#include <filesystem>
#include <iostream>
#include <vector>

using namespace std;


void RecursivelyCopyFile(std::filesystem::path From,std::filesystem::path To,const std::vector<std::string>& FileExtensionsToCopyList)
{
    //create directoy if it does not exist
    if(!std::filesystem::exists(To))
    {
        std::filesystem::create_directory(To);
    }


    std::filesystem::directory_iterator end_itr;

    for (std::filesystem::directory_iterator itr(From); itr != end_itr; ++itr)
    {
        //if it is a directory, recursively call this function
        if (std::filesystem::is_directory(itr->path()))
        {
            std::filesystem::path newTo = To;
            newTo/=(itr->path().filename());
            std::filesystem::create_directory(newTo);
            RecursivelyCopyFile(itr->path(),newTo,FileExtensionsToCopyList);
            continue;
        }

        //check if it is a file
        if (!std::filesystem::is_regular_file(itr->path()))
        {
            continue;
        }

        //check if the extension is in the list
        bool bCopy=false;
        if(FileExtensionsToCopyList.size()==0)
        {
            bCopy=true;
        }
        else
        {
            //check if the extension is in the list
            for(int i=0;i<FileExtensionsToCopyList.size();i++)
            {
                if(itr->path().extension() == FileExtensionsToCopyList[i])
                {
                    //std::cout<<"Found:"<<itr->path().string()<<"\n"<<std::endl;
                    bCopy=true;
                    break;
                }
            }
        }

        if(!bCopy)
        {
            continue;
        }

        //copy the file
        std::filesystem::path newTo = To;
        newTo/=(itr->path().filename());

        //check if the file already exist and is the same 
        if(std::filesystem::exists(newTo))
        {
            if(std::filesystem::file_size(itr->path())==std::filesystem::file_size(newTo)
                && std::filesystem::last_write_time(itr->path())==std::filesystem::last_write_time(newTo)
            )
            {
                continue;
            }
        }

        std::filesystem::copy_file(itr->path(),newTo,std::filesystem::copy_options::overwrite_existing);
        
        //std::cout<<"Copied:"<<itr->path().string()<<" to "<<newTo.string()<<"\n"<<std::endl;

    }    


}


int main(int argc, char* argv[])
{
    //first argument is CopyFrom folder
    //second argument is CopyTo folder
    //third argument is optional, specifies file extensions to copy, separated by comma

    if (argc < 3)
    {
        printf("Not enough arguments\n");

        //print usage
        printf("Usage: CopyFiles <CopyFrom folder> <CopyTo folder> <optional: file extensions to copy, separated by comma>\n");

        return 1;
    }

    std::string copyFromFolder = argv[1];
    std::string copyToFolder = argv[2];   
    std::vector<std::string> fileExtensionsToCopyList;

    if (argc > 3)
    {
        //split the third argument by comma
        std::string fileExtensionsToCopy = argv[3];

        std::string delimiter = ",";

        size_t pos = 0;

        while ((pos = fileExtensionsToCopy.find(delimiter)) != std::string::npos) {
            std::string token = fileExtensionsToCopy.substr(0, pos);
            fileExtensionsToCopyList.push_back(token);
            fileExtensionsToCopy.erase(0, pos + delimiter.length());
        }
        fileExtensionsToCopyList.push_back(fileExtensionsToCopy);
    }

    //print the from to folders
    std::cout<<"Copy from:"<<copyFromFolder<<std::endl;
    std::cout<<"Copy to:"<<copyToFolder<<std::endl;


    RecursivelyCopyFile(copyFromFolder,copyToFolder,fileExtensionsToCopyList);

    //print done
    std::cout<<"Done"<<std::endl;

    return 0;

}